#pragma once

#include <functional>
#include <memory>

#include "noncopyable.h"
#include "Timestamp.h"

class EventLoop;

/**
 * 理清楚 EventLoop、Channel、Poller之间的关系  Reactor模型上对应多路事件分发器
 * Channel理解为通道 封装了sockfd和其感兴趣的event 如EPOLLIN、EPOLLOUT事件 还绑定了poller返回的具体事件
 *
 * Channel 对象封装了文件描述符及其事件处理逻辑，而 epoll_wait() 只告诉我们哪些文件描述符发生了事件，
 * 但并不知道具体的处理逻辑。Channel::handleEvent() 的作用是：
 * 根据 revents_ 的值，判断发生了哪些事件。
 * 调用对应的回调函数，执行具体的事件处理逻辑。
 **/
class Channel : noncopyable
{
public:
    using EventCallback = std::function<void()>; // muduo仍使用typedef
    using ReadEventCallback = std::function<void(Timestamp)>;

    Channel(EventLoop *loop, int fd);
    ~Channel();

    // fd得到Poller通知以后 处理事件 handleEvent在EventLoop::loop()中调用
    void handleEvent(Timestamp receiveTime);

    // 设置回调函数对象
    void setReadCallback(ReadEventCallback cb) { readCallback_ = std::move(cb); }
    void setWriteCallback(EventCallback cb) { writeCallback_ = std::move(cb); }
    void setCloseCallback(EventCallback cb) { closeCallback_ = std::move(cb); }
    void setErrorCallback(EventCallback cb) { errorCallback_ = std::move(cb); }

    /**
     * 在事件处理函数 handleEvent 中，Channel 会检查是否绑定了对象。
     * 如果绑定了对象，则通过 tie_.lock() 将 std::weak_ptr 提升为 std::shared_ptr。
     * 如果提升成功，说明绑定对象仍然存在，事件处理可以继续；如果提升失败，
     * 则说明绑定对象已经被销毁，事件处理将被跳过。
     *
     * 防止当channel被手动remove掉 channel还在执行回调操作
     **/
    void tie(const std::shared_ptr<void> &);

    int fd() const { return fd_; }
    int events() const { return events_; }
    /**
     * set_revents(int revt) 方法的作用是将 Poller 检测到的事件（revt）设置
     * 到 Channel 的 revents_ 成员变量中。这样，Channel 就可以知道文件描述符
     * 在当前轮询周期中实际发生了哪些事件。
     * 在 Channel 的事件处理函数 handleEvent 中，会根据 revents_ 的值来决定调用哪些回调函数
     * 详见handleEventWithGuard
     */
    void set_revents(int revt) { revents_ = revt; }

    // 设置fd相应的事件状态 相当于epoll_ctl add delete
    // kReadEvent = 0 对events没有任何影响
    // kWriteEvent = 1 enable使得events为1 disable使得enent为0
    //  |= 表示添加什么事件   &= 表示删除事件
    void enableReading()
    {
        events_ |= kReadEvent;
        update();
    }
    void disableReading()
    {
        events_ &= ~kReadEvent;
        update();
    }
    void enableWriting()
    {
        events_ |= kWriteEvent;
        update();
    }
    void disableWriting()
    {
        events_ &= ~kWriteEvent;
        update();
    }
    void disableAll()
    {
        events_ = kNoneEvent;
        update();
    }

    // 返回fd当前的事件状态
    bool isNoneEvent() const { return events_ == kNoneEvent; }
    bool isWriting() const { return events_ & kWriteEvent; }
    bool isReading() const { return events_ & kReadEvent; }

    int index() { return index_; }
    void set_index(int idx) { index_ = idx; }

    // one loop per thread
    EventLoop *ownerLoop() { return loop_; }
    void remove();

private:
    void update();
    void handleEventWithGuard(Timestamp receiveTime);

    static const int kNoneEvent;
    static const int kReadEvent;
    static const int kWriteEvent;

    EventLoop *loop_; // 事件循环
    const int fd_;    // fd，Poller监听的对象
    int events_;      // 注册fd感兴趣的事件
    int revents_;     // Poller返回的具体发生的事件
    int index_;

    std::weak_ptr<void> tie_;
    bool tied_;

    // 因为channel通道里可获知fd最终发生的具体的事件events，所以它负责调用具体事件的回调操作
    ReadEventCallback readCallback_;
    EventCallback writeCallback_;
    EventCallback closeCallback_;
    EventCallback errorCallback_;
};